package channel

import (
	"fmt"
	"sync"
	"time"
)

func broadcast() {
	N := 10
	exit := make(chan struct{})
	done := make(chan struct{}, N)

	// start N worker goroutines
	for i := 0; i < N; i++ {
		go isAlive(i, exit, done)
	}

	time.Sleep(3 * time.Second)
	// broadcast exit signal
	close(exit)
	// wait for all worker goroutines exit
	for i := 0; i < N; i++ {
		<-done
	}
	fmt.Println("main goroutine exit")
}

//go func(n int) {
//	for {
//		select {
//		// wait for exit signal
//		case <-exit:
//			fmt.Printf("worker goroutine #%d exit\n", n)
//			done <- struct{}{}
//			return
//		case <-time.After(time.Second):
//			fmt.Printf("worker goroutine #%d is working...\n", n)
//		}
//	}
//}(i)

func isAlive(n int, exit, done chan struct{}) {
	for {
		select {
		// wait for exit signal
		case <-exit:
			fmt.Printf("worker goroutine #%d exit\n", n)
			done <- struct{}{}
			return
		case <-time.After(time.Second):
			fmt.Printf("worker goroutine #%d is working...\n", n)
		}
	}
}

func channel_panic() int {
	println("start main")
	ch := make(chan int, 4)
	go func() {
		for i := 0; i < 10; i++ {
			ch <- i
		}
		// 如果不关闭channel,会引发panic
		close(ch)
	}()

	res := 0
	for v := range ch {
		res += v
	}
	println("end main")
	return res
}

func readInOrder() {
	var wg sync.WaitGroup
	ch := make(chan int, 10)
	done1 := make(chan bool)
	done2 := make(chan bool)
	defer close(ch)
	defer close(done1)
	defer close(done2)
	wg.Add(3)

	go func() {
		//time.Sleep(time.Second * 5)
		for i := 0; i < 100; i++ {
			ch <- i
		}
		done1 <- true
		done2 <- true
		wg.Done()
	}()

	go read(ch, done1, 1, &wg)
	go read(ch, done2, 2, &wg)

	wg.Wait()
}

func read(ch chan int, done chan bool, i int, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		select {
		case n := <-ch:
			fmt.Printf("func %v current number %v \n", i, n)
		case <-done:
			return
		}
	}
}

func escape() {
	var wg sync.WaitGroup

	ch := make(chan int, 10)
	defer close(ch)
	wg.Add(2)

	go func() {
		//time.Sleep(time.Second * 5)
		for i := 0; i < 100; i++ {
			ch <- i
		}
		wg.Done()
	}()

	go escapeRead(ch, 1, &wg)
	go escapeRead(ch, 2, &wg)

	wg.Wait()
}

func escapeRead(ch chan int, i int, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		select {
		case n := <-ch:
			fmt.Printf("func %v current number %v \n", i, n)
			if n == 99 {
				return
			}
		default:
		}
	}
}
